package com.xl.controller;

import cn.hutool.cache.CacheUtil;
import cn.hutool.cache.impl.TimedCache;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.extra.qrcode.QrCodeUtil;
import cn.hutool.extra.qrcode.QrConfig;
import com.xl.domain.entity.UserEntity;
import com.xl.domain.pojo.SessionPojo;
import com.xl.domain.result.AjaxResult;
import com.xl.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.HashMap;
import java.util.Map;

/**
 * 用户登录
 */
@Slf4j
@RestController
@RequestMapping(value = "/user")
public class UserController {

    @Autowired
    private UserService userService;


    /**
     * 缓存放二维码会话，设置1分钟过期
     */
    private TimedCache qrCodeSession= CacheUtil.newTimedCache(1000*60);

    /**
     * 存储token信息
     */
    private TimedCache mobileTokenSession=CacheUtil.newTimedCache(1000*60);


    /**
     * 用户手机端登录方法
     * @return
     */
    @PostMapping(value = "/loginMobile")
    public AjaxResult<Map<String,String>> loginMobile(@RequestBody UserEntity userForm){
         UserEntity userEntity=userService.login(userForm);
         //登录成功
         if(ObjectUtil.isNotNull(userEntity)){
             AjaxResult ajaxResult = AjaxResult.SUCCESS;
             Map<String,String> resultMap=new HashMap<>();
             resultMap.put("username",userEntity.getUsername());
             String tokenId=IdUtil.objectId();
             resultMap.put("token",tokenId);
             log.debug("token={}",tokenId);
             ajaxResult.setData(resultMap);
             //存储到缓存中
             mobileTokenSession.put(tokenId,userEntity);
             return ajaxResult;
         }else{ //登录失败
             return AjaxResult.Fail;
         }
    }


    /**
     * 生成PC端登录二维码
     * @return
     */
    @GetMapping(value = "/pcQrCode")
    public Mono<AjaxResult<Map<String,String>>> pcQrCode(){
        return Mono.create((sink)->{
            //生成会话编号
            String sessionId= IdUtil.objectId();
            log.debug("sessionId={}",sessionId);
            SessionPojo sessionPojo=new SessionPojo();
            sessionPojo.setSessionId(sessionId);
            //0 二维码 生成状态 ，1 扫码状态 2 登录状态
            sessionPojo.setStatus(0);

            //生成base64二维码
            QrConfig qrConfig=new QrConfig();
            qrConfig.setWidth(300);
            qrConfig.setHeight(300);
            String base64Code=QrCodeUtil.generateAsBase64(sessionId, qrConfig,"jpeg");

            //绑定返回体数据
            AjaxResult<Map<String,String>> ajaxResult=AjaxResult.SUCCESS;
            Map<String,String> resultData=new HashMap<>();
            resultData.put("sessionId",sessionId);
            resultData.put("base64Code",base64Code);
            ajaxResult.setData(resultData);

            //存入缓存
            qrCodeSession.put(sessionId,sessionPojo);

            sink.success(ajaxResult);
        });
    }


    /**
     * 监听二维码 session 状态
     * @param sessionId
     * @return
     */
    @GetMapping(value = "/getSessionStatus",produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Mono<AjaxResult<SessionPojo>> getSessionStatus(String sessionId){
        return Mono.create((sink)->{
            SessionPojo sessionPojo =(SessionPojo)qrCodeSession.get(sessionId);
            AjaxResult ajaxResult=AjaxResult.SUCCESS;
            if(ObjectUtil.isNull(sessionPojo)){
                sessionPojo=new SessionPojo();
                sessionPojo.setSessionId(sessionId);
                //0 二维码 生成状态 ，1 扫码成功 2 登录成功  -1 sessionId过期失效
                sessionPojo.setStatus(-1);
            }
            ajaxResult.setData(sessionPojo);
            sink.success(ajaxResult);
        });
    }


    /**
     * 扫码二维码成功
     * @return
     */
    @PostMapping(value = "/mobileScanOk")
    public Mono<AjaxResult> mobileScanOk(ServerWebExchange exchange)
    {

       return exchange.getFormData().flatMap((formData)->{
            //判断二维码session是否有效
            String sessionId = formData.getFirst("sessionId");
            String token=formData.getFirst("token");

            SessionPojo sessionPojo = (SessionPojo) qrCodeSession.get(sessionId);
            if(ObjectUtil.isNull(sessionPojo)){
                AjaxResult ajaxResult=AjaxResult.Fail;
                ajaxResult.setMsg("二维码已失效");
                return Mono.just(ajaxResult);
            }

           //判断token是否有效
           UserEntity userEntity = (UserEntity) mobileTokenSession.get(token);

            //0 二维码 生成状态 ，1 扫码成功 2 登录成功  -1 sessionId过期失效
            mobileTokenSession.get(token);
            sessionPojo.setStatus(1);
            sessionPojo.setUsername(userEntity.getUsername());
            AjaxResult ajaxResult=AjaxResult.SUCCESS;
            ajaxResult.setMsg("扫描成功，等待手机端确认操作");
            return Mono.just(ajaxResult);
        });


    }

    /**
     * 手机端确认登录
     * @return
     */
    @PostMapping(value = "/mobileOkPcLogin")
    public Mono<AjaxResult> mobileOkPcLogin(ServerWebExchange exchange){

        return exchange.getFormData().flatMap(formData -> {
            String sessionId = formData.getFirst("sessionId");
            String token=formData.getFirst("token");

            //判断二维码session是否有效
            SessionPojo sessionPojo = (SessionPojo) qrCodeSession.get(sessionId);
            if (ObjectUtil.isNull(sessionPojo)) {
                AjaxResult ajaxResult = AjaxResult.Fail;
                ajaxResult.setMsg("二维码已失效");
                return Mono.just(ajaxResult);
            }

            //判断token是否有效
            UserEntity userEntity = (UserEntity) mobileTokenSession.get(token);
            if (ObjectUtil.isNull(userEntity)) {
                AjaxResult ajaxResult = AjaxResult.Fail;
                ajaxResult.setMsg("用户信息验证失效");
                return Mono.just(ajaxResult);
            }

            //修改二维码session对象状态
            //0 二维码 生成状态 ，1 扫码成功 2 登录成功  -1 sessionId过期失效
            sessionPojo.setUsername(userEntity.getUsername());
            sessionPojo.setStatus(2);

            AjaxResult ajaxResult = AjaxResult.SUCCESS;
            ajaxResult.setMsg("PC登录成功");
            return Mono.just(ajaxResult);
        });

    }
}
